import time
import logging
from typing import Optional, List
from playwright.sync_api import Page, TimeoutError


class ClickUtils:
    """
    简单直接的点击工具类 - 静态方法
    """
    
    @staticmethod
    def safe_click(page: Page, selector: str, timeout: int = 5000, retries: int = 3, wait_after: float = 1.0) -> bool:
        """
        安全点击元素，自动重试
        
        Args:
            page: 页面对象
            selector: 元素选择器
            timeout: 超时时间（毫秒）
            retries: 重试次数
            wait_after: 点击后等待时间（秒）
            
        Returns:
            bool: 点击成功返回True
        """
        for attempt in range(retries + 1):
            try:
                # 等待元素可点击
                element = page.wait_for_selector(selector, timeout=timeout, state="visible")
                if not element:
                    if attempt < retries:
                        time.sleep(1)
                        continue
                    return False
                
                # 检查元素是否可点击
                if not element.is_visible() or not element.is_enabled():
                    element.scroll_into_view_if_needed()
                    time.sleep(0.5)
                
                # 尝试点击
                element.click(timeout=timeout)
                time.sleep(wait_after)
                return True
                
            except Exception as e:
                if attempt < retries:
                    print(f"点击失败，重试 {attempt + 1}/{retries}: {e}")
                    time.sleep(1)
                else:
                    print(f"点击最终失败: {selector} - {e}")
                    return False
        
        return False
    
    @staticmethod
    def click_and_wait_url_change(page: Page, selector: str, expected_url_parts: List[str], 
                                 timeout: int = 10000, retries: int = 3, wait_after: float = 2.0) -> bool:
        """
        点击按钮并等待URL变化包含指定字符串
        
        Args:
            page: 页面对象
            selector: 按钮选择器
            expected_url_parts: 期望URL包含的字符串列表
            timeout: 超时时间（毫秒）
            retries: 重试次数
            wait_after: 点击后等待时间（秒）
            
        Returns:
            bool: 成功返回True
        """
        for attempt in range(retries + 1):
            try:
                # 记录点击前的URL
                before_url = page.url

                url_matches = all(part in before_url for part in expected_url_parts)
                if url_matches:
                    return  True
                
                # 点击按钮
                if not ClickUtils.safe_click(page, selector, timeout, 1, wait_after):
                    if attempt < retries:
                        print(f"点击失败，重试 {attempt + 1}/{retries}")
                        time.sleep(2)
                        continue
                    return False
                
                # 等待URL变化
                start_time = time.time()
                while (time.time() - start_time) * 1000 < timeout:
                    current_url = page.url
                    
                    # 检查URL是否包含期望的字符串
                    if current_url:
                        url_matches = all(part in current_url for part in expected_url_parts)
                        if url_matches:
                            print(f"URL变化成功: {current_url}")
                            return True
                    
                    time.sleep(0.5)
                
                # 超时，重试
                if attempt < retries:
                    print(f"URL未变化，重试 {attempt + 1}/{retries}. 当前URL: {page.url}")
                    time.sleep(2)
                else:
                    print(f"URL变化失败. 期望包含: {expected_url_parts}, 当前: {page.url}")
                    return False
                    
            except Exception as e:
                if attempt < retries:
                    print(f"操作异常，重试 {attempt + 1}/{retries}: {e}")
                    time.sleep(2)
                else:
                    print(f"操作最终失败: {e}")
                    return False
        
        return False
    
    @staticmethod
    def click_and_wait_element(page: Page, click_selector: str, wait_selector: str, 
                              timeout: int = 10000, retries: int = 3, wait_after: float = 1.0) -> bool:
        """
        点击按钮并等待指定元素出现
        
        Args:
            page: 页面对象
            click_selector: 要点击的元素选择器
            wait_selector: 等待出现的元素选择器
            timeout: 超时时间（毫秒）
            retries: 重试次数
            wait_after: 点击后等待时间（秒）
            
        Returns:
            bool: 成功返回True
        """
        for attempt in range(retries + 1):
            try:
                # 点击按钮
                if not ClickUtils.safe_click(page, click_selector, timeout, 1, wait_after):
                    if attempt < retries:
                        print(f"点击失败，重试 {attempt + 1}/{retries}")
                        time.sleep(2)
                        continue
                    return False
                
                # 等待目标元素出现
                try:
                    element = page.wait_for_selector(wait_selector, timeout=timeout, state="visible")
                    if element and element.is_visible():
                        print(f"目标元素出现: {wait_selector}")
                        return True
                except TimeoutError:
                    if attempt < retries:
                        print(f"目标元素未出现，重试 {attempt + 1}/{retries}")
                        time.sleep(2)
                        continue
                    else:
                        print(f"目标元素最终未出现: {wait_selector}")
                        return False
                        
            except Exception as e:
                if attempt < retries:
                    print(f"操作异常，重试 {attempt + 1}/{retries}: {e}")
                    time.sleep(2)
                else:
                    print(f"操作最终失败: {e}")
                    return False
        
        return False
    
    @staticmethod
    def click_and_wait_text(page: Page, click_selector: str, expected_text: str, 
                           timeout: int = 10000, retries: int = 3, wait_after: float = 1.0) -> bool:
        """
        点击按钮并等待页面包含指定文本
        
        Args:
            page: 页面对象
            click_selector: 要点击的元素选择器
            expected_text: 期望出现的文本
            timeout: 超时时间（毫秒）
            retries: 重试次数
            wait_after: 点击后等待时间（秒）
            
        Returns:
            bool: 成功返回True
        """
        for attempt in range(retries + 1):
            try:
                # 点击按钮
                if not ClickUtils.safe_click(page, click_selector, timeout, 1, wait_after):
                    if attempt < retries:
                        print(f"点击失败，重试 {attempt + 1}/{retries}")
                        time.sleep(2)
                        continue
                    return False
                
                # 等待文本出现
                start_time = time.time()
                while (time.time() - start_time) * 1000 < timeout:
                    try:
                        page_content = page.content()
                        if expected_text in page_content:
                            print(f"目标文本出现: {expected_text}")
                            return True
                    except Exception:
                        pass
                    
                    time.sleep(0.5)
                
                # 超时，重试
                if attempt < retries:
                    print(f"目标文本未出现，重试 {attempt + 1}/{retries}")
                    time.sleep(2)
                else:
                    print(f"目标文本最终未出现: {expected_text}")
                    return False
                    
            except Exception as e:
                if attempt < retries:
                    print(f"操作异常，重试 {attempt + 1}/{retries}: {e}")
                    time.sleep(2)
                else:
                    print(f"操作最终失败: {e}")
                    return False
        
        return False
    
    @staticmethod
    def is_clickable(page: Page, selector: str, timeout: int = 3000) -> bool:
        """
        检查元素是否可点击
        
        Args:
            page: 页面对象
            selector: 元素选择器
            timeout: 超时时间（毫秒）
            
        Returns:
            bool: 可点击返回True
        """
        try:
            element = page.wait_for_selector(selector, timeout=timeout, state="visible")
            if element:
                return element.is_visible() and element.is_enabled()
            return False
        except Exception:
            return False
    
    @staticmethod
    def wait_for_clickable(page: Page, selector: str, timeout: int = 10000) -> bool:
        """
        等待元素变为可点击状态
        
        Args:
            page: 页面对象
            selector: 元素选择器
            timeout: 超时时间（毫秒）
            
        Returns:
            bool: 成功返回True
        """
        start_time = time.time()
        while (time.time() - start_time) * 1000 < timeout:
            if ClickUtils.is_clickable(page, selector, 1000):
                return True
            time.sleep(0.5)
        
        print(f"等待元素可点击超时: {selector}")
        return False
    
    @staticmethod
    def force_click(page: Page, selector: str, timeout: int = 5000) -> bool:
        """
        强制点击元素（多种方式尝试）
        
        Args:
            page: 页面对象
            selector: 元素选择器
            timeout: 超时时间（毫秒）
            
        Returns:
            bool: 成功返回True
        """
        try:
            element = page.wait_for_selector(selector, timeout=timeout)
            if not element:
                return False
            
            # 方式1: 普通点击
            try:
                element.click(timeout=timeout)
                return True
            except Exception:
                pass
            
            # 方式2: 强制点击
            try:
                element.click(force=True, timeout=timeout)
                return True
            except Exception:
                pass
            
            # 方式3: JavaScript点击
            try:
                element.evaluate("element => element.click()")
                return True
            except Exception:
                pass
            
            # 方式4: 鼠标点击
            try:
                box = element.bounding_box()
                if box:
                    page.mouse.click(box['x'] + box['width']/2, box['y'] + box['height']/2)
                    return True
            except Exception:
                pass
            
            return False
            
        except Exception as e:
            print(f"强制点击失败: {selector} - {e}")
            return False
    
    @staticmethod
    def click_with_retry_until_success(page: Page, selector: str, max_attempts: int = 10, 
                                     wait_between: float = 2.0, timeout: int = 5000) -> bool:
        """
        持续重试点击直到成功
        
        Args:
            page: 页面对象
            selector: 元素选择器
            max_attempts: 最大尝试次数
            wait_between: 尝试间隔（秒）
            timeout: 每次尝试的超时时间（毫秒）
            
        Returns:
            bool: 成功返回True
        """
        for attempt in range(max_attempts):
            print(f"尝试点击 {attempt + 1}/{max_attempts}: {selector}")
            
            if ClickUtils.safe_click(page, selector, timeout, 1, 1.0):
                print(f"点击成功: {selector}")
                return True
            
            if attempt < max_attempts - 1:
                print(f"点击失败，等待 {wait_between} 秒后重试...")
                time.sleep(wait_between)
        
        print(f"所有尝试都失败了: {selector}")
        return False


# 使用示例
def example_usage():
    """使用示例"""
    # 假设你有一个page对象
    # page = ...
    
    # 1. 简单点击
    # success = ClickUtils.safe_click(page, ".login-btn")
    
    # 2. 点击并等待URL变化
    # success = ClickUtils.click_and_wait_url_change(
    #     page, 
    #     ".submit-btn", 
    #     ["success", "dashboard"],  # URL需要包含这些字符串
    #     timeout=10000,
    #     retries=3
    # )
    
    # 3. 点击并等待元素出现
    # success = ClickUtils.click_and_wait_element(
    #     page,
    #     ".next-btn",
    #     ".result-panel",  # 等待这个元素出现
    #     timeout=10000
    # )
    
    # 4. 点击并等待文本出现
    # success = ClickUtils.click_and_wait_text(
    #     page,
    #     ".search-btn",
    #     "搜索结果",  # 等待页面包含这个文本
    #     timeout=10000
    # )
    
    # 5. 检查元素是否可点击
    # clickable = ClickUtils.is_clickable(page, ".my-button")
    
    # 6. 等待元素可点击
    # ready = ClickUtils.wait_for_clickable(page, ".my-button", timeout=10000)
    
    # 7. 强制点击
    # success = ClickUtils.force_click(page, ".stubborn-button")
    
    # 8. 持续重试直到成功
    # success = ClickUtils.click_with_retry_until_success(
    #     page, 
    #     ".sometimes-works-button", 
    #     max_attempts=10,
    #     wait_between=3.0
    # )
    
    pass